#!/bin/bash
# kola: { "exclusive": false }
# This is a place to put random quick read-only tests.
set -xeuo pipefail

ok() {
    echo "ok" "$@"
}

fatal() {
    echo "$@" >&2
    exit 1
}

on_platform() {
    grep -q " ignition.platform.id=$1 " /proc/cmdline
}

get_journal_msg_timestamp() {
    journalctl -o json -b 0 --grep "$1" \
        | jq -r --slurp '.[0]["__MONOTONIC_TIMESTAMP"]'
}

# Test some services are enabled or disabled appropriately
for unit in logrotate; do
    if ! systemctl is-enabled ${unit} 1>/dev/null; then
        fatal "Unit ${unit} should be enabled"
    fi
done
# Make sure that kdump didn't start (it's either disabled, or enabled but
# conditional on crashkernel= karg, which we don't bake).
if ! systemctl show -p ActiveState kdump.service | grep -q ActiveState=inactive; then
    fatal "Unit kdump.service shouldn't be active"
fi
# systemd-resolved should be enabled
if ! systemctl is-enabled systemd-resolved 1>/dev/null; then
    fatal "Unit systemd-resolved should be enabled"
fi
# systemd-resolved should be fully functional on f35+
source /etc/os-release
if [ "$VERSION_ID" -ge "35" ]; then
    if ! grep 'nameserver 127.0.0.53' /etc/resolv.conf; then
        fatal "systemd-resolved stub listener isn't enabled"
    fi
fi
ok services

# https://github.com/coreos/fedora-coreos-config/commit/2a5c2abc796ac645d705700bf445b50d4cda8f5f
if ip link | grep -o -e " eth[0-9]:"; then
    fatal "detected eth* NIC naming on node"
fi
ok nic naming

for part in /sysroot /boot; do
    if ! findmnt -n -o options ${part} | grep -q "ro,"; then
        fatal "${part} is missing ro option"
    fi
    if test -w "${part}" || touch "${part}/somefile" 2>/dev/null; then
        fatal "${part} is writable"
    fi
done
ok read-only partitions

if ! lsattr -d / | grep -qe '--i--'; then
    fatal "missing immutable bit on /"
fi
ok immutable bit

# See remove-files in the manifest
if test -d /usr/share/info; then
    fatal "found /usr/share/info"
fi

# Security scanners complain about world-readable files in /etc/sudoers.d.
# Check that there aren't any.
# https://bugzilla.redhat.com/show_bug.cgi?id=1981979
sudoers_files="$(find /etc/sudoers.d -type f ! -perm 600 2>&1)"
if [ -n "$sudoers_files" ]; then
    fatal "Found files in /etc/sudoers.d with unexpected permissions: $sudoers_files"
fi

# See https://github.com/coreos/coreos-assembler/pull/1786
path=/usr/lib/systemd/system-generators/coreos-platform-chrony
mode=$(stat -c '%a' ${path})
if test "${mode}" != 555; then
    fatal "For path ${path} expected mode 555, found ${mode}"
fi

switchroot_ts=$(get_journal_msg_timestamp 'Switching root.')
nm_ts=$(get_journal_msg_timestamp 'NetworkManager .* starting')
# by default, kola on QEMU shouldn't need to bring up networking
# https://github.com/coreos/fedora-coreos-config/pull/426
if [[ $nm_ts -lt $switchroot_ts ]] && on_platform qemu; then
    fatal "NetworkManager started in initramfs!"
# and as a sanity-check that this test works, verify that on AWS
# we did bring up networking in the initrd
elif [[ $nm_ts -gt $switchroot_ts ]] && on_platform aws; then
    fatal "NetworkManager not started in initramfs!"
fi
ok conditional initrd networking

if ! test -f /usr/share/licenses/fedora-coreos-config/LICENSE; then
    fatal missing LICENSE
fi
ok LICENSE

# Defined in https://github.com/coreos/fedora-coreos-tracker/blob/master/internals/README-internals.md#aleph-version
jq < /sysroot/.coreos-aleph-version.json >/dev/null
ok aleph

case "$(arch)" in
    x86_64|aarch64)
        # This is just a basic sanity check; at some point we
        # will implement "project-owned tests run in the pipeline"
        # and be able to run the existing bootupd tests:
        # https://github.com/coreos/fedora-coreos-config/pull/677
        bootupctl status
        ok bootupctl
        ;;
esac

# check that no files are unlabeled
unlabeled=$(find /var /etc -context '*:unlabeled_t:*')
if [ -n "${unlabeled}" ]; then
    echo "Found unlabeled files:"
    echo "${unlabeled}"
    exit 1
fi
ok no files with unlabeled_t SELinux label

# make sure we're using the sqlite rpmdb backend
# https://github.com/coreos/fedora-coreos-tracker/issues/623
if [ ! -f /usr/share/rpm/rpmdb.sqlite ]; then
    fatal "Didn't find file /usr/share/rpm/rpmdb.sqlite"
fi
ok rpmdb is sqlite

# make sure dnsmasq is masked
# https://github.com/coreos/fedora-coreos-tracker/issues/519#issuecomment-705140528
if [ $(systemctl is-enabled dnsmasq.service) != 'masked' ]; then
    fatal "dnsmasq.service systemd unit should be masked"
fi
ok "dnsmasq.service systemd unit is masked"

# make sure systemd-repart is masked
# https://github.com/coreos/fedora-coreos-config/pull/744
if [ $(systemctl is-enabled systemd-repart.service) != 'masked' ]; then
    fatal "systemd-repart.service systemd unit should be masked"
fi
ok "systemd-repart.service systemd unit is masked"

rootflags=$(findmnt /sysroot -no OPTIONS)
if ! grep prjquota <<< "${rootflags}"; then
    fatal "missing prjquota in root mount flags: ${rootflags}"
fi
ok "root mounted with prjquota"

# make sure the system is on cgroups v2
has_cgroup_karg=1
grep -q systemd.unified_cgroup_hierarchy /proc/cmdline || has_cgroup_karg=0
sys_fs_cgroup_source=$(findmnt -no SOURCE /sys/fs/cgroup)
stream=$(rpm-ostree status -b --json | jq -r '.deployments[0]["base-commit-meta"]["fedora-coreos.stream"]')
if [ $has_cgroup_karg == 1 ]; then
    fatal "found systemd.unified_cgroup_hierarchy=0"
fi
if [[ $sys_fs_cgroup_source != cgroup2 ]]; then
    fatal "/sys/fs/cgroup is not cgroup2"
fi

list="$(find /etc -type f,d -perm /022)"
if [[ -n "${list}" ]]; then
	find /etc -type f,d -perm /022 -print0 | xargs -0 ls -al
	fatal "found files or directories with 'g+w' or 'o+w' permission"
fi
ok "no files with 'g+w' or 'o+w' permission found in /etc"

for f in '/etc/passwd' '/etc/group'; do
	if [[ $(stat --format="%a %u %g" "${f}") != "644 0 0" ]]; then
		ls -al "${f}"
		fatal "found incorrect permissions for ${f}"
	fi
done
ok "correct ownership and mode on /etc/passwd & /etc/group"

# We shouldn't pull this into the transaction by default. See
# https://github.com/coreos/fedora-coreos-config/pull/1088
# https://www.freedesktop.org/wiki/Software/systemd/NetworkTarget/
if ! systemctl show -p ActiveState network-online.target | grep -q ActiveState=inactive; then
    fatal "Unit network-online.target shouldn't be active"
fi
ok "unit network-online.target inactive"

# It's easy for dracut modules to accidentally ship scripts without +x set
tmpd=$(mktemp -d)
( cd ${tmpd} && lsinitrd --unpack /boot/ostree/*/init* )
if find ${tmpd}/usr/{bin,sbin,libexec} ! -perm -0111 | grep -v clevis-luks-common-functions; then
    fatal "Found non-executable scripts in initrd"
fi
rm -r ${tmpd}
ok "All initrd scripts are executable"
